using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Data;
using Models;
using Services;

namespace AuthDemo.Controllers
{
    // 身份认证控制器，处理用户注册、登录、令牌刷新等功能
    [ApiController]
    [Route("api/[controller]")]
    public class AuthController : ControllerBase
    {
        // 用户管理器，处理用户创建、密码验证等
        private readonly UserManager<ApplicationUser> _userManager;
        // 登录管理器，处理用户登录
        private readonly SignInManager<ApplicationUser> _signInManager;
        // 配置管理器，用于获取JWT配置等
        private readonly IConfiguration _configuration;
        // 数据库上下文，用于刷新令牌的存储
        private readonly ApplicationDbContext _context;
        // 邮件发送服务，用于发送确认邮件和重置密码邮件
        private readonly IEmailSender _emailSender;

        // 构造函数，注入必要的服务
        public AuthController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            IConfiguration configuration,
            ApplicationDbContext context,
            IEmailSender emailSender)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _configuration = configuration;
            _context = context;
            _emailSender = emailSender;
        }

        /// <summary>
        /// 用户注册接口
        /// </summary>
        /// <param name="model">注册模型，包含邮箱、密码等信息</param>
        /// <returns>注册结果</returns>
        [HttpPost("register")]
        public async Task<IActionResult> Register(RegisterModel model)
        {
            // 创建新用户
            var user = new ApplicationUser 
            { 
                UserName = model.Email, 
                Email = model.Email,
                FirstName = model.FirstName,
                LastName = model.LastName
            };

            // 尝试创建用户
            var result = await _userManager.CreateAsync(user, model.Password);
            
            if (result.Succeeded)
            {
                // 生成邮箱确认令牌
                var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                // 创建确认链接
                var confirmationLink = Url.Action(nameof(ConfirmEmail), "Auth", 
                    new { token, email = user.Email }, Request.Scheme);

                // 发送确认邮件
                if (user.Email != null)
                {
                    await _emailSender.SendEmailAsync(user.Email, "确认您的邮箱",
                        $"请点击此链接确认您的邮箱: {confirmationLink}");
                }

                // 将用户添加到默认角色
                await _userManager.AddToRoleAsync(user, "User");
                return Ok(new { Message = "Please check your email to confirm your account" });
            }

            return BadRequest(result.Errors);
        }

        /// <summary>
        /// 用户登录接口
        /// </summary>
        [HttpPost("login")]
        public async Task<IActionResult> Login(LoginModel model)
        {
            // 验证用户凭据
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null)
            {
                return BadRequest("Invalid credentials");
            }

            var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
            if (!result.Succeeded)
            {
                return BadRequest("Invalid credentials");
            }

            var token = await GenerateJwtToken(user);
            var refreshToken = GenerateRefreshToken(user.Id);
            
            _context.RefreshTokens.Add(refreshToken);
            await _context.SaveChangesAsync();

            return Ok(new { 
                Token = token,
                RefreshToken = refreshToken.Token
            });
        }

        [HttpPost("refresh-token")]
        public async Task<IActionResult> RefreshToken(RefreshTokenRequest request)
        {
            var refreshToken = await _context.RefreshTokens
                .Include(r => r.User)
                .FirstOrDefaultAsync(r => r.Token == request.RefreshToken);

            if (refreshToken == null || 
                refreshToken.ExpiryDate < DateTime.UtcNow || 
                refreshToken.IsRevoked ||
                refreshToken.User == null)
            {
                return BadRequest("Invalid refresh token");
            }

            var newToken = await GenerateJwtToken(refreshToken.User);
            var newRefreshToken = GenerateRefreshToken(refreshToken.UserId);

            refreshToken.IsRevoked = true;
            _context.RefreshTokens.Add(newRefreshToken);
            await _context.SaveChangesAsync();

            return Ok(new { 
                Token = newToken,
                RefreshToken = newRefreshToken.Token
            });
        }

        [HttpGet("confirm-email")]
        public async Task<IActionResult> ConfirmEmail(string token, string email)
        {
            var user = await _userManager.FindByEmailAsync(email);
            if (user == null)
                return BadRequest("Invalid email");

            var result = await _userManager.ConfirmEmailAsync(user, token);
            if (result.Succeeded)
                return Ok("Email confirmed successfully");

            return BadRequest("Error confirming email");
        }

        [HttpPost("forgot-password")]
        public async Task<IActionResult> ForgotPassword(ForgotPasswordModel model)
        {
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null || user.Email == null)
                return Ok(); // Don't reveal that the user does not exist

            var token = await _userManager.GeneratePasswordResetTokenAsync(user);
            var resetLink = Url.Action(nameof(ResetPassword), "Auth",
                new { token, email = user.Email }, Request.Scheme);

            await _emailSender.SendEmailAsync(user.Email, "重置密码",
                $"请点击此链接重置密码: {resetLink}");

            return Ok(new { Message = "Please check your email to reset your password" });
        }

        [HttpPost("reset-password")]
        public async Task<IActionResult> ResetPassword(ResetPasswordModel model)
        {
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null)
                return BadRequest("Invalid email");

            var result = await _userManager.ResetPasswordAsync(user, model.Token, model.Password);
            if (result.Succeeded)
                return Ok(new { Message = "Password has been reset" });

            return BadRequest(result.Errors);
        }

        /// <summary>
        /// 生成刷新令牌
        /// </summary>
        private RefreshToken GenerateRefreshToken(string userId)
        {
            return new RefreshToken
            {
                Token = Guid.NewGuid().ToString(),    // 生成唯一标识符
                ExpiryDate = DateTime.UtcNow.AddDays(7), // 7天后过期
                UserId = userId,
                IsRevoked = false
            };
        }

        /// <summary>
        /// 生成JWT访问令牌
        /// </summary>
        private async Task<string> GenerateJwtToken(ApplicationUser user)
        {
            // 创建声明列表
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id ?? ""),
                new Claim(ClaimTypes.Email, user.Email ?? "")
            };

            // 添加用户角色
            var roles = await _userManager.GetRolesAsync(user);
            foreach (var role in roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            }

            // 创建JWT令牌
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtSettings:SecretKey"] ?? ""));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var expires = DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["JwtSettings:ExpirationInMinutes"]));

            var token = new JwtSecurityToken(
                issuer: _configuration["JwtSettings:Issuer"],
                audience: _configuration["JwtSettings:Audience"],
                claims: claims,
                expires: expires,
                signingCredentials: creds
            );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
} 